{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 四类参数\n",
    "- 普通参数\n",
    "- 默认参数\n",
    "- 关键字参数\n",
    "- 收集参数\n",
    "\n",
    "## 关键字参数开始\n",
    "- 语法\n",
    "    \n",
    "        def func(p1=v1, p2=v2.....):\n",
    "            func_body\n",
    "            \n",
    "        调用函数：\n",
    "        func(p1=value1, p2=value2.......)\n",
    "- 比较麻烦，但也有好处：\n",
    "    - 不容易混淆， 一般实参和形参只是按照位置一一对应即可，容易出错\n",
    "    - 使用关键字参数，可以不考虑参数位置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I am a student\n",
      "我叫 18， 我今年 jingjing岁了， 我住我家\n",
      "I am a student\n",
      "我叫 jingjing， 我今年 18岁了， 我住我家\n"
     ]
    }
   ],
   "source": [
    "# 关键字参数案例\n",
    "def stu(name, age, addr):\n",
    "    print(\"I am a student\")\n",
    "    print(\"我叫 {0}， 我今年 {1}岁了， 我住{2}\".format(name, age, addr))\n",
    "    \n",
    "    \n",
    "n = \"jingjing\"\n",
    "a = 18\n",
    "addr = \"我家\"\n",
    "\n",
    "# 普通参数，只按照位置传递，容易出错\n",
    "stu(a, n, addr)\n",
    "\n",
    "\n",
    "def stu_key(name=\"No name\", age=0, addr=\"No addr\"):\n",
    "    print(\"I am a student\")\n",
    "    print(\"我叫 {0}， 我今年 {1}岁了， 我住{2}\".format(name, age, addr))\n",
    "    \n",
    "    \n",
    "n = \"jingjing\"\n",
    "a = 18\n",
    "addr = \"我家\"\n",
    "\n",
    "# 普通参数，只按照位置传递，容易出错\n",
    "stu_key(age=a, name=n, addr=addr)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 收集参数\n",
    "- 把没有位置，不能和定义时的参数位置相对应的参数，放入一个特定的数据结构中\n",
    "- 语法\n",
    "    \n",
    "        def func(*args):\n",
    "            func_body\n",
    "            按照list使用方式访问args得到传入的参数\n",
    "            \n",
    "        调用：\n",
    "        func(p1, p2, p3, .....)\n",
    "- 参数名args不是必须这么写，但是，我们推荐直接用args，约定俗成\n",
    "- 参数名args前需要由星号\n",
    "- 收集参数可以和其他参数共存"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello 大家好，我自我介绍以下，简答说两句：\n",
      "<class 'tuple'>\n",
      "liuying\n",
      "18\n",
      "北京大通州区\n",
      "wangxiaojing\n",
      "single\n",
      "Hello 大家好，我自我介绍以下，简答说两句：\n",
      "<class 'tuple'>\n",
      "周大神\n"
     ]
    }
   ],
   "source": [
    "# 收集参数代码\n",
    "# 函数模拟一个学生进行自我介绍，但具体内容不清楚\n",
    "# args把他看做一个list\n",
    "def stu( *args):\n",
    "    print(\"Hello 大家好，我自我介绍以下，简答说两句：\")\n",
    "    # type函数作用是检测变量的类型\n",
    "    print(type(args))\n",
    "    for item in args:\n",
    "        print(item)\n",
    "\n",
    "\n",
    "stu(\"liuying\", 18, \"北京大通州区\", \"wangxiaojing\", \"single\")\n",
    "\n",
    "stu(\"周大神\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello 大家好，我自我介绍以下，简答说两句：\n",
      "<class 'tuple'>\n"
     ]
    }
   ],
   "source": [
    "# 收集参数案例\n",
    "# 说明收集参数可以不带任何实参调用，此时收集参数为空tuple\n",
    "stu()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "stu() got an unexpected keyword argument 'name'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-12-b698f7b62960>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# 如果使用关键字参数格式调用，会出现问题\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mstu\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"liuying\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: stu() got an unexpected keyword argument 'name'"
     ]
    }
   ],
   "source": [
    "# 如果使用关键字参数格式调用，会出现问题\n",
    "stu(name=\"liuying\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ### 收集参数之关键字收集参数\n",
    " - 把关键字参数按字典格式存入收集参数\n",
    " - 语法：\n",
    "     \n",
    "         def func( **kwargs):\n",
    "             func_body\n",
    "             \n",
    "         # 调用：\n",
    "         func(p1=v1, p2=v2, p3=v3........)\n",
    "- kwargs一般约定俗成\n",
    "- 调用的时候，把多余的关键字参数放入kwargs\n",
    "- 访问kwargs需要按字典格式访问"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello 大家好，我先自我介绍一下：\n",
      "<class 'dict'>\n",
      "name --- liuying\n",
      "age --- 19\n",
      "addr --- 北京大通州区\n",
      "lover --- 王晓静\n",
      "work --- Teacher\n",
      "**************************************************\n",
      "Hello 大家好，我先自我介绍一下：\n",
      "<class 'dict'>\n",
      "name --- 周大神\n"
     ]
    }
   ],
   "source": [
    "# 收集参数案例\n",
    "# 自我介绍\n",
    "# 调用的时候需要使用关键字参数调用\n",
    "def stu( **kwargs):\n",
    "    # 在函数体内对于kwargs的使用不用带星号\n",
    "    print(\"Hello 大家好，我先自我介绍一下：\")\n",
    "    print(type(kwargs))\n",
    "    # 对于字典的访问，python2 和python3有区别\n",
    "    for k,v in kwargs.items():\n",
    "        print(k, \"---\", v)\n",
    "    \n",
    "stu(name=\"liuying\",  age=19, addr=\"北京大通州区\", lover=\"王晓静\", work=\"Teacher\")\n",
    "\n",
    "print(\"*\" * 50)\n",
    "\n",
    "stu(name=\"周大神\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello 大家好，我先自我介绍一下：\n",
      "<class 'dict'>\n"
     ]
    }
   ],
   "source": [
    "# 收集参数可以为空案例\n",
    "stu()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 收集参数混合调用的顺序问题\n",
    "- 收集参数，关键字参数，普通参数可以混合使用\n",
    "- 使用规则就是，普通参数和关键字参数优先\n",
    "- 定义的时候一般找普通参数，关键字参数，收集参数tuple，收集参数dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello 大家好\n",
      "我叫 liuying， 我今年19大了。\n",
      "我没有爱好， so sorry\n",
      "********************\n",
      "##############################\n",
      "Hello 大家好\n",
      "我叫 liuying， 我今年19大了。\n",
      "我的爱好是游泳\n",
      "********************\n",
      "##############################\n",
      "Hello 大家好\n",
      "我叫 liuying， 我今年19大了。\n",
      "我的爱好是游泳\n",
      "********************\n",
      "王晓静\n",
      "刘石头\n",
      "##############################\n",
      "hobby2 --- 烹饪\n",
      "hobby3 --- 跟不同女生聊天\n"
     ]
    }
   ],
   "source": [
    "# 收集参数混合调用案例\n",
    "# stu模拟一个学生的自我介绍\n",
    "def stu(name, age, *args, hobby=\"没有\", **kwargs):\n",
    "    print(\"Hello 大家好\")\n",
    "    print(\"我叫 {0}， 我今年{1}大了。\".format(name, age))\n",
    "    if hobby == \"没有\":\n",
    "        print(\"我没有爱好， so sorry\")\n",
    "    else:\n",
    "        print(\"我的爱好是{0}\".format(hobby))\n",
    "        \n",
    "    print(\"*\" * 20)   \n",
    "    \n",
    "    for i in args:\n",
    "        print(i)\n",
    "    \n",
    "    print(\"#\" * 30)\n",
    "    \n",
    "    for k,v in kwargs.items():\n",
    "        print(k, \"---\", v)\n",
    "        \n",
    "        \n",
    "# 开始调用函数\n",
    "name = \"liuying\"\n",
    "age = 19\n",
    "\n",
    "\n",
    "# 调用的不同格式\n",
    "stu(name, age)\n",
    "\n",
    "stu(name, age, hobby=\"游泳\")\n",
    "\n",
    "stu(name, age, \"王晓静\", \"刘石头\", hobby=\"游泳\", hobby2=\"烹饪\", hobby3=\"跟不同女生聊天\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 收集参数的解包问题\n",
    "- 把参数放入list或者字典中，直接把list/dict中的值放入收集参数中\n",
    "- 语法：参看案例\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "哈哈哈哈哈\n",
      "<class 'str'>\n",
      "0\n",
      "liuying\n",
      "<class 'int'>\n",
      "1\n",
      "19\n",
      "<class 'int'>\n",
      "2\n",
      "23\n",
      "<class 'str'>\n",
      "3\n",
      "wangxiaojing\n"
     ]
    }
   ],
   "source": [
    "# 收集参数的解包问题\n",
    "\n",
    "def stu(*args):\n",
    "    print(\"哈哈哈哈哈\")\n",
    "    # n 用来表示循环次数\n",
    "    # 主要用来调试\n",
    "    n = 0\n",
    "    for i in args:\n",
    "        print(type(i))\n",
    "        print(n)\n",
    "        n += 1\n",
    "        print(i)\n",
    "        \n",
    "        \n",
    "#stu(\"liuying\", \"liuxiaoyhing\", 19, 200)\n",
    "\n",
    "l = [\"liuying\", 19, 23, \"wangxiaojing\"]\n",
    " \n",
    "#stu(l)\n",
    "# 此时，args的表示形式是字典内一个list类型的元素，即 arg = ([\"liuying\", 19, 23, \"wangxiaojing\"],)\n",
    "# 很显然跟我们最初的想法违背\n",
    "\n",
    "\n",
    "# 此时的调用，我们就需要解包符号，即调用的时候前面加一个星号\n",
    "stu(*l)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 同理，dict类型收集参数一样可以解包，但是\n",
    "- 对dict类型进行解包\n",
    "- 需要用两个星号进行解包"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 返回值\n",
    "- 函数和过程的区别\n",
    "    - 有无返回值\n",
    "- 需要用return显示返回内容，\n",
    "- 如果没有返回，则默认返回None\n",
    "- 推荐写法，无论有无返回值，最后都要以return 结束"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "有返回值呀\n",
      "1\n",
      "没有返回值\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "# 返回值示例\n",
    "\n",
    "def func_1():\n",
    "    print(\"有返回值呀\")\n",
    "    return 1\n",
    "\n",
    "def func_2():\n",
    "    print(\"没有返回值\")\n",
    "     \n",
    "    \n",
    "f1 = func_1()\n",
    "print(f1)\n",
    "\n",
    "f2 = func_2()\n",
    "print(f2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 函数文档\n",
    "- 函数的文档的作用是对当前函数提供使用相关的参考信息\n",
    "- 文档的写法：\n",
    "    - 在函数内部开始的第一行使用三引号字符串定义符\n",
    "    - 一般具有特定格式\n",
    "    - 参看案例\n",
    "- 文档查看\n",
    "    - 使用help函数，形如 help(func)\n",
    "    - 使用__doc__, 参看案例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 文档案例\n",
    "# 函数stu是模拟一个学生的自我介绍的内容\n",
    "def stu(name, age, *args):\n",
    "    '''\n",
    "    这是第一行\n",
    "    这是第二行\n",
    "    这是第三行\n",
    "    '''\n",
    "    print(\"This is hanshu stu\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function stu in module __main__:\n",
      "\n",
      "stu(name, age, *args)\n",
      "    这是第一行\n",
      "    这是第二行\n",
      "    这是第三行\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n    这是第一行\\n    这是第二行\\n    这是第三行\\n    '"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 查看函数文档\n",
    "help(stu)\n",
    "stu.__doc__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function stu in module __main__:\n",
      "\n",
      "stu(name, age)\n",
      "    这是文档的文字内容\n",
      "    :param name: 表示学生的姓名\n",
      "    :param age: 表示学生的年龄\n",
      "    :return: 此函数没有返回值\n",
      "\n",
      "None\n",
      "********************\n",
      "\n",
      "    这是文档的文字内容\n",
      "    :param name: 表示学生的姓名\n",
      "    :param age: 表示学生的年龄\n",
      "    :return: 此函数没有返回值\n",
      "    \n"
     ]
    }
   ],
   "source": [
    "\n",
    "def stu(name, age):\n",
    "    '''\n",
    "    这是文档的文字内容\n",
    "    :param name: 表示学生的姓名\n",
    "    :param age: 表示学生的年龄\n",
    "    :return: 此函数没有返回值\n",
    "    '''\n",
    "    pass\n",
    "\n",
    "\n",
    "print(help(stu))\n",
    "\n",
    "print(\"*\" * 20)\n",
    "\n",
    "print(stu.__doc__)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
